Skip to main content

Computational Logic Before 2026.1.0

Before ADITO 2026.1.0, row calculation did not use one consistent preparation strategy across all Entity access paths. This mainly affected logic that processed several rows one after another, such as table loading in the UI, entities.getRows, and Entity Webservices.

For customizing developers, this means that calculated values, display values, and dependency-based logic could behave differently depending on how the same Entity data was loaded.

warning

Conclusion: When you maintain projects before ADITO 2026.1.0, do not assume that a calculation tested in the UI behaves identically in entities.getRows or in an Entity Webservice. Validate custom logic in the access path where it is used.


In a nutshell

  • jditoCalculationVersion: V1 (deprecated) or V2 (default)
  • different calculation mechanism for processing several rows on after another in:
    • UI components – for example, a table
    • entities.getRows
    • Entity Webservice
  • results in inconsistent behavior, different results and different runtime performance

Preferences jditoCalculationVersion

The jditoCalculationVersion is a setting, to configure the calculation mode.

  • V1 existed for a long time in the system, but is already deprecated since years. It is worse than V2 in regard to determining and keeping dependencies, which result results in more calculations at which leads to performance issues.
  • V2 is the default mode and offers a more consistent approach to dependency regocnition. It is therefor more performant and allows better optimization on entity-level.

Because V1 is deprecated for so long and will be removed with future versions, we will only cover the V2 behaviour here. Learn more about V2 in Understanding Variable Dependencies.

Multi-row Processing

Row Preparation During Multi-Row Processing

When several records are processed in sequence, ADITO internally prepares the row state before loading the next record. Before version 2026.1.0, different parts of the platform used different approaches for this preparation.

Figure: Simplified model of repeated row preparation and processing during multi-row loading.

An Example

The following table shows five rows that are loaded one after another. Before the first row is loaded, the calculation starts from an initial state that does not contain row values. Each loaded row then creates a new situation for the calculation engine.

IDOrganisation NameTurnover (Several rows)State
a7f3c9e4-5b2d-4f8a-9c1e-3d7b8a6f4e2cGlobal Tech Solutions2,450,000.00active
b8e4d0f5-6c3e-5g9b-0d2f-4e8c9b7g5f3dInnovate Industries1,750,500.50active
c9f5e1g6-7d4f-6h0c-1e3g-5f9d0c8h6g4eFax Manufacturing and Repair1,230.75inactive
d0g6f2h7-8e5g-7i1d-2f4h-6g0e1d9i7h5fNextGen Enterprises3,125,780.25active
e1h7i2j8-9f6g-8h7i-9j8k-7i9l0j1k2l3mGlobal Tech Solutions2,450,000.00delete

Example raw data for a table of five organizations.

Depending on the row processing approach, the calculation differs from one row to the next. Take a look at the different approaches in the following sections.

Overview

ApproachUsed when
Calculate once initially, only calculate differences afterwardreading rows with Entity Webservice
Do nothing, only calculate differences between rowsreading rows with entities.getRows
Reset field values to a fresh start for each rowreading rows within the UI, for example: tables, titled list, card view, etc.

Approach: Calculate once initially, only calculate differences afterward

Behavior: No field reset was performed before the next row was loaded. Impact: Calculated values start from null or from a virtual row state that did not exist in the RecordContainer. Changes do trigger recalculations. Overall better performance, though values may not be as expected.

Example: Looking at the example data above this leads to:

IDNAMEturnoverSTATEisActive
a7f3c9e4-5b2d-4f8a-9c1e-3d7b8a6f4e2cGlobal Tech Solutions0activetrue
b8e4d0f5-6c3e-5g9b-0d2f-4e8c9b7g5f3dInnovate Industries0activetrue
c9f5e1g6-7d4f-6h0c-1e3g-5f9d0c8h6g4eFax Manufacturing and Repair0inactivefalse
d0g6f2h7-8e5g-7i1d-2f4h-6g0e1d9i7h5fNextGen Enterprises0activetrue
e1h7i2j8-9f6g-8h7i-9j8k-7i9l0j1k2l3mGlobal Tech Solutions0deletefalse

Constraints for the turnover value:

  • is calculated from other data in the system
  • defaults to 0
  • is only calculated as long this.value is null

In our example, the first calculation basis is null for the virtual row. This leads to a turnover value of 0 that is not calculated again.

Constraints for the isActive value:

  • is calculated based on the state
  • defaults to false
  • does NOT check if this.value is null

In our example, the first calculation basis is null for the virtual row. This leads to an isActive value of false. Because the dependent value from the state changed, the calculation is triggered again and leads to the expected value.

Approach: Do nothing, only calculate differences between rows

Behavior: No field reset is performed before the next row is loaded, and no initial calculation is performed before the first real row is loaded. Only differences between the currently loaded row and the previously loaded row triggered recalculations.

Impact: Calculated values could keep the value from the first row that calculated them. This was usually faster than resetting fields for every row, but calculations that depended on an implicit fresh start could produce stale values for later rows.

Example: Looking at the example data above this leads to:

IDNAMEturnoverSTATEisActive
a7f3c9e4-5b2d-4f8a-9c1e-3d7b8a6f4e2cGlobal Tech Solutions2,450,000.00activetrue
b8e4d0f5-6c3e-5g9b-0d2f-4e8c9b7g5f3dInnovate Industries2,450,000.00activetrue
c9f5e1g6-7d4f-6h0c-1e3g-5f9d0c8h6g4eFax Manufacturing and Repair2,450,000.00inactivefalse
d0g6f2h7-8e5g-7i1d-2f4h-6g0e1d9i7h5fNextGen Enterprises2,450,000.00activetrue
e1h7i2j8-9f6g-8h7i-9j8k-7i9l0j1k2l3mGlobal Tech Solutions2,450,000.00deletefalse

Constraints for the turnover value:

  • is calculated from other data in the system
  • defaults to 0
  • is only calculated as long this.value is null

In this approach, the first real row starts with a turnovers this.value as null. The turnover is therefore calculated for the first organization. Because the field is not reset afterward, this.value is no longer null for the following rows. The guarded calculation is not executed again, so the later rows keep the turnover value from the first row.

Constraints for the isActive value:

  • is calculated based on the state
  • defaults to false
  • does NOT check if this.value is null

In this approach, isActive is calculated for the first row and then recalculated whenever the dependent state value changes between rows. The second row keeps true, because the state remains active. The following rows recalculate the value when the state changes to inactive, active, and delete.

Approach: Reset field values to a fresh start for each row

Behavior: Field values and display values are reset before each row is loaded. Each row is then calculated from a fresh field state. This reset only affects value and displayValue, but not other field processes such as dropDownProcess.

Impact: Calculated values did not keep state from the previously processed row. This matched the UI behavior, but it is significantly slower because every row requires a resource intensive recalculation.

Example: Looking at the example data above this leads to:

IDNAMEturnoverSTATEisActive
a7f3c9e4-5b2d-4f8a-9c1e-3d7b8a6f4e2cGlobal Tech Solutions2,450,000.00activetrue
b8e4d0f5-6c3e-5g9b-0d2f-4e8c9b7g5f3dInnovate Industries1,750,500.50activetrue
c9f5e1g6-7d4f-6h0c-1e3g-5f9d0c8h6g4eFax Manufacturing and Repair1,230.75inactivefalse
d0g6f2h7-8e5g-7i1d-2f4h-6g0e1d9i7h5fNextGen Enterprises3,125,780.25activetrue
e1h7i2j8-9f6g-8h7i-9j8k-7i9l0j1k2l3mGlobal Tech Solutions2,450,000.00deletefalse

Constraints for the turnover value:

  • is calculated from other data in the system
  • defaults to 0
  • is only calculated as long this.value is null

In this approach, every row starts with a turnovers this.value of null because the field is reset before the row is processed. The turnover calculation is therefore executed for each row and returns the row-specific value.

Constraints for the isActive value:

  • is calculated based on the state
  • defaults to false
  • does NOT check if this.value is null

In this approach, isActive is recalculated for each row from the freshly loaded state value. Because the field state is reset before every row, the result does not depend on the state of the previously processed row.

Consequences of this behavior

The most significant consequence is not only performance. The same Entity could produce different calculated results depending on whether the data was loaded in the UI, through Entity access methods, or through an Entity Webservice. It also makes customization harder because the result is different for different access paths. This can easily lead to bugs that are hard to track down as they only present under certain circumstances.


tl;dr – Why This Matters for Customizing within the UnifiedEntityModel

Custom logic is most vulnerable when it relies on implicit row state. Typical examples are:

  • valueProcess or displayValueProcess logic that reads other EntityFields whose values are calculated.
  • onValueChange logic that is triggered while rows are loaded or recalculated.
  • Calculations that assume an empty or freshly initialized field state for each row.
  • Calculations that behave differently when the first calculation basis is null.

In these cases, the reset strategy can change the result because the calculation may see different previous values, missing values, or recalculated values.

note

The issue is often easier to understand with Entities that contain several calculated fields and dependencies. Organisation_entity is a useful example for checking this behavior in legacy projects.


For projects that stay on a version before 2026.1.0, treat row calculations as access-path-specific behavior:

  1. Test calculated values in the exact access path that is used in production, for example UI table loading, entities.getRows, or an Entity Webservice.
  2. Avoid custom logic that depends on fields being reset implicitly before every row.
  3. Initialize values explicitly inside custom logic when the calculation requires a known starting value.
  4. Pay special attention to valueProcess and displayValueProcess implementations in Entities with many rows, because full recalculation can have a noticeable performance impact.

If a project is migrated to ADITO 2026.1.0 or later, review this logic together with the new row recalculation mode. See Computational Logic Starting With 2026.1.0.